#ifndef OBJECT_H
#define OBJECT_H

#include "varDict.h"
#include "aspect.h"

namespace sge {

class Object;

typedef std::map<String,Object*> StringObjectPtrMap;
typedef std::list<Object*> ObjectPtrList;
typedef std::map<String,StringList> StringStringListMap;

class Object : public VarDict {
private:

    //tree
    String type, name, path;
    Object* parent;
    StringObjectPtrMap children;
    StringList childrenToRemove;
    
    Object(const String& _name, const String& _type, Object* _parent);
    bool removeChildNow(const String& childName);
    void fixPath();
    
    //time
    bool initialized, active, destroyed;
    StringList initDependencies, destroyDependencies;
    
    void processInitDependencies();
    void processDestroyDependencies();
    
    //aspects
    StringAspectPtrMap aspects;
    
    Aspect* aspectFactory(const String& aspectName);

    //files
    StringList includeList;
    StringList fileSearchPaths;
    PythonObject pythonClass;
    
    void initFileSearchPaths();
    
    void loadObject(PythonObject yamlDict);
    void loadVars(PythonObject yamlDict);
    void loadAspects(PythonObject yamlDict);
    void loadChildren(PythonObject yamlDict);
    void loadIncludes(PythonObject yamlDict);
    void loadInitDependencies(PythonObject yamlDict);
    void loadDestroyDependencies(PythonObject yamlDict);
    void loadScriptFiles(PythonObject yamlDict);
    void loadScriptActions(PythonObject yamlDict);
    
    PythonObject saveObject(bool rec);
    PythonObject saveAspects();
    PythonObject saveChildren();
    PythonObject saveIncludes();
    PythonObject saveInitDependencies();
    PythonObject saveDestroyDependencies();
    
    //scripts
    bool madeScriptServer;
    StringStringListMap scriptActions;
    
    bool hasScriptCmd(const String& cmd);
    
    //messages
    StringList subscriberList;
    
public:
    //tree
    static Object root;
    
    ~Object();
    
    Object* addChild(const String& childName, const String& childType);
    Object* getChild(const String& childName);
    bool hasChild(const String& childName) const;
    StringObjectPtrMap& getChildren();
    StringList getChildNames();
    void removeChild(const String& childName);
    
    Object* getObject(const String& objectPath);
    bool hasParent() const;
    Object* getParent() const;
    Object* getRoot();
    
    Object* getFirstObjectOfName(const String& objName, bool fromRoot = true);
    ObjectPtrList getAllObjectsOfName(const String& objName, bool fromRoot = true);
    Object* getFirstObjectOfType(const String& objType, bool fromRoot = true);
    ObjectPtrList getAllObjectsOfType(const String& objType, bool fromRoot = true);
    
    Object* pyGetFirstObjectOfName1(const String& objName);
    Object* pyGetFirstObjectOfName2(const String& objName, bool fromRoot);
    Object* pyGetFirstObjectOfType1(const String& objName);
    Object* pyGetFirstObjectOfType2(const String& objName, bool fromRoot);
    
    String getName() {return name;}
    String getType() {return type;}
    String getPath() {return path;}
    
    PythonObject pyGetChildNames();
    
    //time
    bool init();
    bool update(float time, float dtime);
    bool destroy();
    bool getActive() const;
    void setActive(bool _active);
    void addInitDependency(const String& dependPath);
    void addDestroyDependency(const String& dependPath);
    
    //log
    void log(const char* format, ...);
    void pyLog(const String& str);
    
    //aspects
    bool hasAspect(const String& aspectName);
    Aspect* getAspect(const String& aspectName);
    bool removeAspect(const String& aspectName);
    Aspect* addAspect(const String& aspectName);
    void pyAddAspect(const String& aspectName);
    
    //vars
    void onSetVar(const String& varName);
    void onGetVar(const String& varName);
    Vector3 makeVector(float x, float y, float z);
    Quaternion makeQuaternion(Vector3 a, float a);
    
    //files
    bool findFile(const String& filename, String& result);
    PythonObject pyFindFile(const String& filename);
    bool load(const String& filename);
    void save(const String& filename, bool rec = true);
    void pySave1(const String& filename);
    void pySave2(const String& filename, bool rec);
    
    //scripts
    bool loadScriptFile(const String& filename);
    bool hasScriptAction(const String& cmd, const String& actionName);
    bool addScriptAction(const String& cmd, const String& actionName);
    bool removeScriptAction(const String& cmd, const String& actionName);
    static void registerPythonBindings();
    
    //messages
    bool subscribe(const String& objPath);
    bool isSubscribed(const String& objPath);
    bool unsubscribe(const String& objPath);
    void publish(const String& cmd, const VarDict& args);
    void pyPublish(const String& cmd, boost::python::dict args);
    void receiveMessage(const String& cmd, const VarDict& args);
};

}

#endif
